package com.example.administrator.myview.util;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.drawable.AnimationDrawable;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.example.administrator.myview.BuildConfig;
import com.example.administrator.myview.R;

import org.json.JSONObject;

/**
 * 简化 请求数据-》消息处理-》解析数据流程 ，主要包含以下两种情况
 * 	 -1.不添加NetLayout网络提示    流程           handlerThread(context)
 * 									 -> setHandlerThread(new ThreadCallBack())
 * 								  	 -> doThreadStart(bShowWaiting,sMethodName,sMethodParam)
 * 
 * 	 -2.添加NetLayout网络提示       流程     	 handlerThread(context)
 * 									 -> initNetLayout(layAll,layDisAll)
 *								  	 -> setHandlerThread(new ThreadCallBack())
 *								  	 -> doThreadStartWithNet(bShowWaiting,sMethodName,sMethodParam)
 *
 * 在activity 或fragment 上创建后该类对象后，需要实现 ThreadCallBack接口以下2个方法
 * 	 -ProcessStatusSuccess(JSONObject obj) 获取状态码成功，即 1，解析返回的json数据，并操作相应的Ui显示
 *	 -ProcessStatusError(int errType, int errCode, String errMsg);	错误类型，错误代码，错误信息	errType{0：网络故障；1：JSON解析错误；2：接口返回错误｝
 */ 
@SuppressLint("InflateParams")
public class HandlerThread {
	private Context mContext;
	private Handler mHandler;						//后台数据交互handler
	private LinearLayout layoutNetLoading = null;	//加载中转圈layout
	private LinearLayout layoutNetError = null;		//加载失败layout
	private ImageView ivLoading;					//加载转圈图片
	private ViewGroup layLinDisAll;					//要显示布局
	private TextView txtLoadHint;					//显示等待的提示文字信息
	private boolean mRetryAction = false;			//是否接口处理网络重试加载动作
	private boolean mOwnAlert =false;          		//自己通知加载(例如在通知下拉刷新控件通知加载完成，或者自定义加载圈)
	private Fragment fragment ;						//如果fragment调用此类, 在接口返回响应数据要添加 isAdd()判断
	private String mMethodName;						//接口方法名
	private String mMethodParam;					//接口参数
	private ThreadCallBack mCallBack;				//接口回调
	
	/**
	 * 创建接口类（Activity调用）
	 * @param context	上下文
	 */
	public HandlerThread(Context context){
		mContext = context;
	}
	
	/**
	 * 创建接口类（Activity调用）
	 * @param context		上下文
	 * @param bOwnAlert		是否自己处理错误消息
	 * 						true：自己在回调里面处理；
	 * 						false：交给这个类处理！
	 */
	public HandlerThread(Context context, Boolean bOwnAlert){	
		mContext = context;
		mOwnAlert = bOwnAlert;
	}
	
	/**
	 * 创建接口类（FragmentActivity调用）
	 * @param fragment	上下文
	 */
	public  HandlerThread(Fragment fragment){
		mContext = fragment.getActivity();
		this.fragment =fragment;
	}
	
	/**
	 * 创建接口类（FragmentActivity调用）
	 * @param fragment		上下文
	 * @param bOwnAlert		是否自己处理错误消息
	 * 						true：自己在回调里面处理；
	 * 						false：交给这个类处理！
	 */
	public HandlerThread(Fragment fragment, Boolean bOwnAlert){
		mContext = fragment.getActivity();
		this.fragment =fragment;
		mOwnAlert = bOwnAlert;
	}

	/**
	 * 初始化引导进度和加载错误重试面板
	 * @param layAll		整个显示面板
	 * @param layDisAll		显示内容面板
	 */
	public void initNetLayout(FrameLayout layAll,ViewGroup layDisAll){
		layLinDisAll =layDisAll;
		View viewLoading = LayoutInflater.from(mContext).inflate(R.layout.layout_loading_error, null);
		layAll.addView(viewLoading);
		layoutNetLoading = (LinearLayout) viewLoading.findViewById(R.id.layNetLoading);
		layoutNetLoading.setVisibility(View.GONE);
		layoutNetError = (LinearLayout) viewLoading.findViewById(R.id.layNetError);
		layoutNetError.setVisibility(View.GONE);
		txtLoadHint = (TextView) viewLoading.findViewById(R.id.txtLoadHint);
		txtLoadHint.setVisibility(View.GONE);
		ivLoading = (ImageView)viewLoading.findViewById(R.id.imgLoading);
		Button btnNetRetry = (Button) viewLoading.findViewById(R.id.btnNetRetry);
		btnNetRetry.setOnClickListener(new OnClickListener() {
			 @Override
			public void onClick(View v) {
				 doThreadStartWithNet(true,mMethodName,mMethodParam);
			 }
		});
		mRetryAction =true;
	}
	
	/**
	 * 设置回调 
	 * @param callBack	回调接口函数
	 */
	public void setHandlerThread( ThreadCallBack callBack){
		mCallBack = callBack;
	}
	
	/**
	 * 后台数据请求（带进度文字提示信息）
	 * @param bShowWaiting  是否显示加载进度圈，
	 * 						true：背景半透，阻塞式调用，适合等待型调用（大部分），比如：登陆，修改密码；
	 * 						false：非阻塞式调用，适用非等待式调用，比如：后台获取购物车商品数、各状态订单数等；
	 * @param MethodName	接口方法
	 * @param MethodParam	请求参数
	 * @param sWaitHint		提示的文字信息，让用户知道当前在干嘛（如果bShowWaiting为false忽略此参数）
	 */
	public void doThreadStart(Boolean bShowWaiting,String MethodName,String MethodParam, String sWaitHint){
		mRetryAction = false;
		mMethodName = MethodName;
		mMethodParam = MethodParam;
		initHandler();
		MyHttpThread thread = new MyHttpThread(mHandler);
		thread.doStart(mContext, bShowWaiting,"服务器baseUrl地址", MethodName, MethodParam, sWaitHint);
	}

	/**
	 * 后台数据请求
	 * @param bShowWaiting  是否显示加载进度圈，
	 * 						true：背景半透，阻塞式调用，适合等待型调用（大部分），比如：登陆，修改密码；
	 * 						false：非阻塞式调用，适用非等待式调用，比如：后台获取购物车商品数、各状态订单数等；
	 * @param MethodName	接口方法
	 * @param MethodParam	请求参数
	 */
	public void doThreadStart(Boolean bShowWaiting,String MethodName,String MethodParam){
		doThreadStart(bShowWaiting, MethodName, MethodParam, "");
	}

	/**
	 * 后台数据请求，添加网络重试加载布局提示（带进度文字提示信息）
	 * @param bRetryAction	是否接口处理重试动作，
	 * 						true：接口处理（大部分操作）；
	 * 						false：交给调用的地方处理，适用于：下拉刷新、上拽更多的listview控件；
	 * @param MethodName	接口方法
	 * @param MethodParam	请求参数
	 * @param sWaitHint		提示的文字信息，让用户知道当前在干嘛；
	 */
	public void doThreadStartWithNet(Boolean bRetryAction,String MethodName,String MethodParam, String sWaitHint){
		mRetryAction = bRetryAction;
		if (mRetryAction) {
			layLinDisAll.setVisibility(View.GONE);
			layoutNetError.setVisibility(View.GONE);
			layoutNetLoading.setVisibility(View.VISIBLE);
			if (sWaitHint.length()>0) {	//有提示信息
				txtLoadHint.setText(sWaitHint);
				txtLoadHint.setVisibility(View.VISIBLE);
			}
			((AnimationDrawable) ivLoading.getBackground()).start();
		}
		mMethodName = MethodName;
		mMethodParam = MethodParam;
		initHandler();
		MyHttpThread thread = new MyHttpThread(mHandler);
		thread.doStart(mContext, false,"服务器url地址", MethodName, MethodParam, sWaitHint);
	}
	
	/**
	 * 后台数据请求，添加网络重试加载布局提示
	 * @param bRetryAction	是否接口处理重试动作，
	 * 						true：接口处理（大部分操作）；
	 * 						false：交给调用的地方处理，适用于：下拉刷新、上拽更多的listview控件；
	 * @param MethodName	接口方法
	 * @param MethodParam	请求参数
	 */
	public void doThreadStartWithNet(Boolean bRetryAction,String MethodName,String MethodParam){
		doThreadStartWithNet(bRetryAction, MethodName, MethodParam, "");
	}
	
	//消息处理
	@SuppressLint("HandlerLeak")
	private void initHandler(){
		if(mHandler !=null) return;
		mHandler = new Handler(mContext.getMainLooper()){
	        public void handleMessage(Message m){
	        	String strReturn = m.getData().getString("data");
	        	if (fragment!= null && !fragment.isAdded()) return ;      //当前fragment被移除，不加载后台数据或toast
	        	if (mRetryAction) layoutNetLoading.setVisibility(View.GONE);	//隐藏等待窗体
	            switch(m.what){
	            case 1:	//调用成功返回数据
	            	ParseJsonData(strReturn);	//解析接口返回的json数据
	       			break;     
	       			
	            case 2:	//调用出错
	            	if (mRetryAction) {
	            		layoutNetError.setVisibility(View.VISIBLE);
	            	}
	            	String sError ="网络不给力";	//这位同学，网络不给力啊，请检查一下您的网络，重新加载吧！
	            	if(BuildConfig.DEBUG) {
	            		sError = strReturn;	//调试模式返回详细信息
	            	}
		            if (mOwnAlert) {
		            	mCallBack.ProcessStatusError(0, 0, sError);
		            } else {
		            	Toast.makeText(mContext, sError, Toast.LENGTH_LONG).show();
		            }
		            break;
	            }
	        }
		};
	}
	
	//分析json数据
	private void ParseJsonData(String strReturn) {
        try {
            //这地方根据后台来定义
	        JSONObject obj = new JSONObject(strReturn); 
			String status = "0", statusMsg = "";
	        if (obj.has("status")) status = obj.getString("status");  
	        if (obj.has("statusMsg")) statusMsg = obj.getString("statusMsg");  
	        if (status.equals("1")) {	//接口返回成功
	        	if(mRetryAction) {
	        		layLinDisAll.setVisibility(View.VISIBLE);//放在回调方法上面，有时候连续调用多个接口，调完一个接口不想显示布局;
	        	}
	        	mCallBack.ProcessStatusSuccess(obj);
	        }
	        else {	//接口返回错误
	        	int errCode = MyUtils.StringToInt(status);
	        	if (mOwnAlert) {
	        		mCallBack.ProcessStatusError(2, errCode, statusMsg.substring(0, Math.min(255, statusMsg.length())));
	        	} else {
	        		Toast.makeText(mContext,statusMsg.substring(0, Math.min(255, statusMsg.length())), Toast.LENGTH_LONG).show();	//服务器返回错误：
	        	}
	        }
        } catch (Exception e) {	//服务器返回的数据格式有误 
        	e.printStackTrace();
           	if (mOwnAlert) {
           		mCallBack.ProcessStatusError(1, 0, "网络不给力");
           	} else {
           		Toast.makeText(mContext, "网络不给力", Toast.LENGTH_LONG).show();
           	}
        }
	}
	
	//回调接口
	public interface ThreadCallBack{
		void ProcessStatusSuccess(JSONObject obj) throws Exception;
		/**
		 * 返回错误信息数据 
		 * @param errType	错误类型	0:网络通信故障，1:json格式解析失败，2:服务器接口返回错误；
		 * @param errCode	错误代码	详见各接口文档
		 * @param errMsg	错误信息	直接返回给前端
		 */
		void ProcessStatusError(int errType, int errCode, String errMsg);	
	}
	
}

